package com.example.framework509.common.services.Impl;

import com.example.framework509.common.entities.MapperParam;
import com.example.framework509.common.services.ManyToManyMapperService;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ManyToManyAutoMapperImpl<E,PRIMARY_CLASS,SECONDARY_CLASS> extends AutoMapperServiceImpl<E,PRIMARY_CLASS,SECONDARY_CLASS> implements ManyToManyMapperService<E> {

    @Override
    protected void addMapperInRedis(MapperParam param) {
        redisUtil.sSet(ENTITY_NAME_LOWER+PRIMARY_FIELD_NAME+":"+param.getPrimaryId(),param.getSecondaryId());
        redisUtil.sSet(ENTITY_NAME_LOWER+SECONDARY_FIELD_NAME+":"+param.getSecondaryId(),param.getPrimaryId());
    }

    @Override
    protected void delMapperInRedis(MapperParam param) {
        redisUtil.setRemove(ENTITY_NAME_LOWER+PRIMARY_FIELD_NAME+":"+param.getPrimaryId(),param.getSecondaryId());
        redisUtil.setRemove(ENTITY_NAME_LOWER+SECONDARY_FIELD_NAME+":"+param.getSecondaryId(),param.getPrimaryId());
    }

    @Override
    protected boolean hasSameMapper(Integer primaryId, Integer secondaryId) {
        Set<Object> res = redisUtil.sGet(ENTITY_NAME_LOWER+PRIMARY_FIELD_NAME+":"+primaryId);
        if (res==null)
            return false;
        return res.contains(secondaryId);
    }

    @Override
    public Set<Integer> getSecondaryIdsFromPrimaryId(Integer primaryId) {

        getAllEntityNum();

        Set<Object> res = redisUtil.sGet(ENTITY_NAME_LOWER+PRIMARY_FIELD_NAME+":"+primaryId);
        Set<Integer> childrenIds = new HashSet<>();
        if (res == null || res.size() == 0) {
            return new HashSet<>();
        }
        else {
            for (Object idStr : res) {
                int idInt = Integer.parseInt((idStr).toString());
                childrenIds.add(idInt);
            }
        }
        return childrenIds;
    }

    @Override
    public Set<Integer> getPrimaryIdsFromSecondaryId(Integer secondaryId) {
        getAllEntityNum();

        Set<Object> res = redisUtil.sGet(ENTITY_NAME_LOWER+SECONDARY_FIELD_NAME+":"+secondaryId);
        Set<Integer> childrenIds = new HashSet<>();
        if (res == null || res.size() == 0) {
            return new HashSet<>();
        }
        else {
            for (Object idStr : res) {
                int idInt = Integer.parseInt((idStr).toString());
                childrenIds.add(idInt);
            }
        }
        return childrenIds;
    }

    public List<PRIMARY_CLASS> getPrimaryEntityFromSecondaryId(Integer secondaryId){
        Set<Integer> primaryIdsFromSecondaryId = getPrimaryIdsFromSecondaryId(secondaryId);
        List<PRIMARY_CLASS> entities = new ArrayList<>();
        for (Integer id:primaryIdsFromSecondaryId){
            entities.add(primaryEntityBaseService.getEntityFromId(id));
        }
        return entities;
    }

    public List<SECONDARY_CLASS> getSecondaryEntityFromPrimaryId(Integer primaryId){
        Set<Integer> secondaryIdsFromPrimaryId = getSecondaryIdsFromPrimaryId(primaryId);
        List<SECONDARY_CLASS> entities = new ArrayList<>();
        for (Integer id:secondaryIdsFromPrimaryId){
            entities.add(secondaryEntityBaseService.getEntityFromId(id));
        }
        return entities;
    }

    @Override
    protected void editSecFetchCallBack(Integer primaryId, List<Integer> secondaryIds) throws Exception {
        Set<Integer> secondaryIdsFromPrimaryId = getSecondaryIdsFromPrimaryId(primaryId);
        List<Integer> secondaryIdsFromDB = new ArrayList<>(secondaryIdsFromPrimaryId);
        List<Integer> delIds = computeSubtraction(secondaryIdsFromDB, secondaryIds);
        delMapperFetch(primaryId,delIds);
        List<Integer> addIds = computeSubtraction(secondaryIds, secondaryIdsFromDB);
        addMapperFetch(primaryId,addIds);
    }

    @Override
    protected void editPriFetchCallBack(Integer secondaryId, List<Integer> primaryIds) throws Exception {
        Set<Integer> primaryIdsFromSecondaryId = getPrimaryIdsFromSecondaryId(secondaryId);
        List<Integer> primaryIdsFromDB = new ArrayList<>(primaryIdsFromSecondaryId);
        List<Integer> delIds = computeSubtraction(primaryIdsFromDB, primaryIds);
        delPriMapperFetch(secondaryId,delIds);
        List<Integer> addIds = computeSubtraction(primaryIds, primaryIdsFromDB);
        addPriMapperFetch(secondaryId,addIds);
    }
}
